package ar.com.spsolutions.splibrary.services.google.books;

import java.io.Serializable;
import java.lang.reflect.Type;

import ar.com.spsolutions.splibrary.author.Author;
import ar.com.spsolutions.splibrary.book.Book;
import ar.com.spsolutions.splibrary.book.category.Category;
import ar.com.spsolutions.splibrary.services.AuthorService;
import ar.com.spsolutions.splibrary.services.CategoryService;
import ar.com.spsolutions.splibrary.services.LibraryServiceFacade;

import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

public class BookDeserializer implements JsonDeserializer<Book>, Serializable {
	private static final long serialVersionUID = 1969297385628960747L;

	private LibraryServiceFacade libraryServiceFacade;

	public BookDeserializer(final LibraryServiceFacade libraryServiceFacade) {
		this.setLibraryServiceFacade(libraryServiceFacade);
	}

	@Override
	public Book deserialize(final JsonElement json, final Type typeOfT,
			final JsonDeserializationContext context) throws JsonParseException {
		final Book book = new Book();
		final JsonObject volumeInfo = json.getAsJsonObject().get("volumeInfo")
				.getAsJsonObject();
		book.setTitle(this.toString(volumeInfo, "title"));
		book.setPublisher(this.toString(volumeInfo, "publisher"));
		final Author author = this.getAuthor(volumeInfo);
		book.setAuthor(author);
		book.setIsbn(this.getISBN13(volumeInfo));
		book.setStars(this.getStars(volumeInfo));
		// book.setPic("bookPic/Libro X.jpg");
		book.setPic(this.getPic(volumeInfo));
		book.setDescription(this.getDescription(volumeInfo));
		this.addCategories(book, volumeInfo);
		return book;
	}

	private String getPic(final JsonObject volumeInfo) {
		final JsonElement imageLinks = volumeInfo.get("imageLinks");
		if (imageLinks == null) {
			return "bookPic/Libro X.jpg";
		}
		return imageLinks.getAsJsonObject().get("thumbnail").getAsString();
	}

	private String getDescription(final JsonObject volumeInfo) {
		return volumeInfo.get("description").getAsString();
	}

	private Integer getStars(final JsonObject volumeInfo) {
		return volumeInfo.get("averageRating").getAsInt();
	}

	private String getISBN13(final JsonObject jsonObject) {
		final JsonArray isbns = jsonObject.get("industryIdentifiers")
				.getAsJsonArray();
		final JsonObject isbn13 = isbns.get(1).getAsJsonObject();
		return isbn13.get("identifier").getAsString();
	}

	private void addCategories(final Book book, final JsonObject volumeInfo) {
		final JsonElement categories = volumeInfo.get("categoties");
		if (categories != null) {
			final JsonArray categoriesArray = categories.getAsJsonArray();
			for (int i = 0; i < categoriesArray.size(); i++) {
				final String categoryName = categoriesArray.get(i)
						.getAsString();
				Category aCategory = this.getCategoryService().findByName(
						categoryName);
				if (aCategory == null) {
					aCategory = new Category();
					aCategory.setName(categoryName);
				}
				book.addCategory(aCategory);
			}
		}
	}

	private CategoryService getCategoryService() {
		return this.getLibraryServiceFacade().getEntityService()
				.getCategoryService();
	}

	private Author getAuthor(final JsonObject jsonObject) {
		final JsonElement authors = jsonObject.get("authors");
		String authorName = "";
		if (authors != null) {
			final JsonElement author = authors.getAsJsonArray().get(0);
			if (author != null) {
				authorName = author.getAsString();
			}
		}
		Author author = this.getAuthorService().findByName(authorName);
		if (author == null) {
			author = new Author();
			author.setName(authorName);
		}
		return author;
	}

	private AuthorService getAuthorService() {
		return this.getLibraryServiceFacade().getEntityService()
				.getAuthorService();
	}

	private String toString(final JsonObject jsonObject, final String property) {
		final JsonElement jsonElement = jsonObject.get(property);
		return jsonElement == null ? "" : jsonElement.getAsString();
	}

	public LibraryServiceFacade getLibraryServiceFacade() {
		return this.libraryServiceFacade;
	}

	public void setLibraryServiceFacade(
			final LibraryServiceFacade libraryServiceFacade) {
		this.libraryServiceFacade = libraryServiceFacade;
	}

}
